
#include <drv_st7735.h>
#include <drv_spi.h>

static init_buf st7735_init_buf =
        { .len = init_buf_arg_len, .data[0] = { 0x11, 0, { 0 } }, .data[1] = { 0xff, 0, { 0 } }, { 0xB1, 3, { 0x05,
                0x3c, 0x3c } }, { 0xB2, 3, { 0x05, 0x3c, 0x3c } }, { 0xB3, 6, { 0x05, 0x3c, 0x3c, 0x05, 0x3c, 0x3c } },
                { 0xb4, 1, { 0x03 } }, { 0xc0, 3, { 0x28, 0x08, 0x04 } }, { 0xc1, 1, { 0xc0 } }, { 0xc2, 2,
                        { 0x0d, 0x00 } }, { 0xc3, 2, { 0x8d, 0x2a } }, { 0xc4, 2, { 0x8d, 0xee } },
                { 0xc5, 1, { 0x1a } },
#if USE_HORIZONTAL == 0
                {   0x36, 1,
                    {   0xC0}},
#elif USE_HORIZONTAL == 1
                {   0x36, 1,
                    {   0x00}},
#elif USE_HORIZONTAL == 2
                { 0x36, 1, { 0xA0 } },
#else
                {   0x36, 1,
                    {   0x60}},
#endif
                { 0xE0, 16, { 0x04, 0x22, 0x07, 0x0A, 0x2e, 0x30, 0x25, 0x2a, 0x28, 0x26, 0x2e, 0x3a, 0x00, 0x01, 0x03,
                        0x13 } }, { 0xE1, 16, { 0x04, 0x16, 0x06, 0x0d, 0x2d, 0x26, 0x23, 0x27, 0x27, 0x25, 0x2d, 0x3b,
                        0x00, 0x01, 0x04, 0x13 } }, { 0x3A, 1, { 0x05 } }, { 0x29, 0, { 0x00 } },
                //{0x21,0,0},
                { 0xff, 0, { 0x00 } }, };


static struct rt_spi_device *spi_dev_lcd;

#define LCD_SPI_BUS_NAME "spi1"
#define LCD_SPI_DEV_NAME "spi_lcd"


void LCD_Writ_Bus(uint8_t dat)
{
    LCD_CS_Clr();
    //HAL_SPI_Transmit(&hspi1, &dat, 1, 0xff);
    LCD_CS_Set();
}

void LCD_WR_DATA8(u8* dat)
{
    LCD_CS_Clr();
    rt_spi_send(spi_dev_lcd, dat, 1);
    LCD_CS_Set();
}

void LCD_WR_DATA_DMA(u8* dat, u16 len)
{
    LCD_CS_Clr();

    rt_spi_send(spi_dev_lcd, dat, len);
//    HAL_SPI_Transmit_DMA(&hspi1, dat, len);
//    HAL_DMA_StateTypeDef ret = HAL_DMA_STATE_BUSY;
//    while(1){
//        ret = HAL_DMA_GetState(&hdma_spi1_tx);
//        if(ret == HAL_DMA_STATE_READY)break;
//    };
    LCD_CS_Set();
}

void LCD_WR_DATA(u16 dat)
{
#if TRANSMIT_DMA
    uint8_t temp[] = {  dat>>8, dat&0xff };
    LCD_WR_DATA_DMA(temp,2);
#else
    LCD_Writ_Bus(dat >> 8);
    LCD_Writ_Bus(dat);
#endif
}

void LCD_WR_REG(u8 dat)
{
    LCD_DC_Clr();
#if TRANSMIT_DMA
    LCD_WR_DATA_DMA(&dat,1);
#else
    LCD_Writ_Bus(dat);
#endif
    LCD_DC_Set();
}


void st7735_rst(void)
{
    LCD_RS_Clr();
    rt_thread_mdelay(100);
    LCD_RS_Set();
    rt_thread_mdelay(100);
}

/*void print_struct(init_buf* dat)
 {
 printf("dat->len : %d\r\n",dat->len);
 for (int i = 0; i < dat->len; ++i) {
 printf("dat->data[%d].reg : 0x%X\r\n",i,dat->data[i].reg);
 if (dat->data[i].arg_len == 0)continue;
 for (int j = 0; j < dat->data[i].arg_len; ++j) {
 printf("dat->data[%d].args : 0x%X\r\n",i,dat->data[i].args[j]);
 }
 }
 }*/

void struct_send(init_buf* dat)
{
    //print_struct(dat);
    for (int i = 0; i < dat->len; ++i)
    {
        //delay_us(2);
        LCD_WR_REG(dat->data[i].reg);

#if TRANSMIT_DMA
        if (dat->data[i].arg_len == 0)continue;
        LCD_WR_DATA_DMA(dat->data[i].args,dat->data[i].arg_len);
#else
        for (int j = 0; j < dat->data[i].arg_len; ++j)
        {
            LCD_Writ_Bus(dat->data[i].args[j]);
        }
#endif
    }
}

void LCD_Address_Set(u16 x1, u16 y1, u16 x2, u16 y2)
{
#if 1 == USE_HORIZONTAL || USE_HORIZONTAL == 0
    init_buf args_buf =
    {
        .len = 3,
        .data[0] =
        {   0x2a, 4,
            {   0x00,(uint8_t)x1,0x00,(uint8_t)x2}},
        .data[1] =
        {   0x2b, 4,
            {   0x00,(uint8_t)y1,0x00,(uint8_t)y2}},
        .data[2] =
        {   0x2c, 0,0x00}};
#else
    init_buf args_buf = { .len = 3, .data[0] = { 0x2a, 4, { 0x00, (uint8_t) x1, 0x00, (uint8_t) x2 } }, .data[1] = {
            0x2b, 4, { 0x00, (uint8_t) y1, 0x00, (uint8_t) y2 } }, .data[2] = { 0x2c, 0, { 0x00 } } };
#endif
    struct_send(&args_buf);
}

void lcd_register_init(void)
{
    LCD_WR_REG(0x11);
    delay_ms(100);
    for (int i = 0; i < st7735_init_args.len; ++i)
    {
        if (st7735_init_args.data[i].reg == 0xff)
            delay_ms(100);
        else
        {
            LCD_WR_REG(st7735_init_args.data[i].reg);
#if TRANSMIT_DMA
            if (st7735_init_buf.data[i].arg_len == 0)continue;
            LCD_WR_DATA_DMA(st7735_init_buf.data[i].args,st7735_init_buf.data[i].arg_len);
#else
            for (int j = 0; j < st7735_init_args.data[i].arg_len; ++j)
            {
                LCD_Writ_Bus(st7735_init_args.data[i].args[j]);
            }
#endif
        }
    }
}
static int rt_hw_lcd_config(void)
{
    spi_dev_lcd = (struct rt_spi_device *)rt_device_find(LCD_SPI_DEV_NAME);

    if (spi_dev_lcd == NULL) {
        rt_kprintf("can not find %s device.\n", LCD_SPI_DEV_NAME);
        return -RT_ERROR;
    }
    /* config spi */
    {
        struct rt_spi_configuration cfg;
        cfg.data_width = 8;
        cfg.mode = RT_SPI_MASTER | RT_SPI_MODE_3 | RT_SPI_MSB | RT_SPI_NO_CS;
        cfg.max_hz = 18 * 1000 * 1000; /* 42M,SPI max 42MHz,lcd 4-wire spi */

        rt_spi_configure(spi_dev_lcd, &cfg);
        rt_kprintf("%s device config successful.\n", LCD_SPI_DEV_NAME);
    }

    return RT_EOK;
}

void rt_hw_lcd_gpio_init(void)
{
    int lcd_cs_pin,lcd_blk_pin,lcd_dc_pin,lcd_rst_pin;
    lcd_dc_pin  = GET_PIN(B,7);
    lcd_blk_pin = GET_PIN(B,4);
    lcd_cs_pin  = GET_PIN(A,15);
    lcd_rst_pin = GET_PIN(B,6);

    rt_pin_mode(lcd_dc_pin , PIN_MODE_OUTPUT);
    rt_pin_mode(lcd_blk_pin, PIN_MODE_OUTPUT);
    rt_pin_mode(lcd_cs_pin , PIN_MODE_OUTPUT);
    rt_pin_mode(lcd_rst_pin, PIN_MODE_OUTPUT);

    rt_pin_write(lcd_blk_pin, PIN_HIGH);
    st7735_rst();
}


void lcd_device_init(void)
{
    rt_hw_spi_device_attach(LCD_SPI_BUS_NAME, LCD_SPI_DEV_NAME, GPIOA, GPIO_PIN_15);
    rt_hw_lcd_gpio_init();
    rt_hw_lcd_config();
    lcd_register_init();
}

